﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Data.Common;
using System.Linq.Expressions;
using Storage.EntityModels;
using System.Text;
using NUnit.Framework;
using Search;
using System.Globalization;
using GeoRef;
using System.IO;

namespace SearchUnitTests
{
    /// <summary>
    /// This is the unit test class.
    /// </summary>
    [TestFixture]
    public class Tests
    {
        [Test]
        public void runSpider()
        {
            SpiderManager sm = SpiderManager.Create(CultureInfo.GetCultureInfo("en"));
            Assert.IsNotNull(sm);
            sm.RunSpider();
        }

        [Test]
        public void fullTextSearch()
        {
            IEnumerable<FullTextResult> res = null;
            string outSuggestion;
            res = SearchManager.FullTextSearch("rambo", CultureInfo.GetCultureInfo("it"), out outSuggestion);
            Assert.IsNotNull(res);

            Console.WriteLine("Forse intendevi " + outSuggestion + " ?");
            foreach (FullTextResult r in res)
                Console.WriteLine(r.Link + " Title:" + r.Snippet);

            }

        [Test]
        public void fullTextSearchPaginated()
        {
            IEnumerable<FullTextResult> res = null;
            res = SearchManager.FullTextSearch("termostato", 10, 5);
            Assert.IsNotNull(res);

            foreach (FullTextResult r in res)
                Console.WriteLine(r.Link + " Title:" + r.Snippet);
        }

        [Test]
        public void userSearch()
        {
            ParameterExpression param = Expression.Parameter(typeof(User), "u");
            Expression<Func<User, bool>> cond = u => u.Username.Contains("lampa");
            Expression<Func<User, bool>> cond2 = u => u.DrivingLicence.Value;

            Expression cond3 = Expression.And(Expression.Invoke(cond, param), Expression.Invoke(cond2, param));
            
            Expression<Func<User, bool>> predicate = Expression.Lambda<Func<User, bool>>(cond3, param);

            IEnumerable<User> list = getDummyUsers().AsQueryable().Where<User>(predicate);

            Assert.AreEqual(1, list.Count<User>());

            User lampa = list.First<User>();
            Assert.AreEqual("d.lampa", lampa.Username);

        }

        [Test]
        public void realUserSearch()
        {
            UserParameter username = UserParameter.Create<string>("Username", n => n.Contains("m"));
            UserParameter date = UserParameter.Create<int?>("Age",
                d => d.HasValue && d.Value > 20);
            UserParameter gender = UserParameter.Create<byte>("Gender", g => g == (byte)Gender.Female);

            UserParameter feed = UserParameter.Create<EntitySet<PassengerFeedback>>("ReceivedPassengerFeedbacks",
                p => p.Average<PassengerFeedback>(f => f.GenericVote) >= 5);
            UserParameter smoker = UserParameter.Create<byte>("Smoker", n => n == (byte)Smoker.NotSmoker || n == (byte)Smoker.Unknown);

            List<UserParameter> paramz = new List<UserParameter>();
            paramz.Add(username);
            //paramz.Add(date);
            paramz.Add(smoker);
            paramz.Add(gender);
            paramz.Add(feed);

            IEnumerable<User> users = SearchManager.UserSearch(paramz);
            
            
            DbCommand cmd = Storage.StorageManager.Instance.Entities.GetCommand(users.AsQueryable<User>());
            Console.WriteLine(cmd.CommandText);

            foreach (User u in users)
                Console.WriteLine("ID: {0}, Username: {1}, {2}, {3}, {4}, {5}",
                    u.Id,
                    u.Username,
                    u.Smoker,
                    u.Age,
                    u.Gender,
                    u.ReceivedPassengerFeedbacks.Count > 0 ? u.ReceivedPassengerFeedbacks.Average<PassengerFeedback>(f => f.GenericVote) : 0);
        }

        [Test]
        public void realTripSearch()
        {
            TripParameter partenza = new TripParameter(new GeoPoint(1, 2), 2000, true);
            TripParameter arrivo = new TripParameter(new GeoPoint(31, 34), 2000, true);

            DateTime dataViaggio = new DateTime(2008, 4, 23);

            TripFieldParameter data = TripFieldParameter.Create<DateTime?>("DepartureDate",
                d => d.HasValue && d.Value.Date == dataViaggio);

            List<TripFieldParameter> paramz = new List<TripFieldParameter>();
            paramz.Add(data);

            IEnumerable<Trip> trips = SearchManager.TripSearch(TripParameter.Empty, arrivo, paramz, null);

           //cmd = Storage.StorageManager.Instance.Entities.GetCommand(trips);
            //Console.WriteLine(cmd.CommandText);

            foreach (Trip t in trips)
                Console.WriteLine(t.Id);

        }

        public List<User> getDummyUsers()
        {
            List<User> dummyList = new List<User>();

            User u = new User();
            u.Address = "Indirizzo di prova";
            u.Name = "Dario Lampa";
            u.Username = "d.lampa";
            u.DrivingLicence = true;
            u.Birthday = new DateTime(1986, 12, 4);
            //u.Vehicles = new List<Vehicle>();
            dummyList.Add(u);
            
            User t = new User();
            t.Address = "Indirizzo falso";
            t.Birthday = new DateTime(1984, 12, 5);
            t.DrivingLicence = false;
            t.Name = "Thomas Turbato";
            t.Username = "t.turbato";

            return dummyList;
        }

        [Test]
        public void TestConfig()
        {
            Assert.IsNotNull(SearchConfig.Instance.IndexFolder);
            Assert.IsNotNull(SearchConfig.Instance.SpiderFrequency);
            Assert.IsNotNull(SearchConfig.Instance.SpiderUrl);

        }

        [Test]
        public void TestSelectTrip()
        {
            Table<Trip> trips = Storage.StorageManager.Instance.Entities.Trips;

            var q = from t in trips
                    where t.Stages.OrderBy<Stage, Int16>(s => s.Ordinal).First<Stage>().Origin.Id == 140
                    select t;

            foreach (Trip t in q)
            {
                Console.WriteLine(t.Id);
            }

        }

        [Test]
        public void TestSelectUser()
        {
            Table<User> users = Storage.StorageManager.Instance.Entities.Users;

            var c = from u in users
                    where u.ReceivedPassengerFeedbacks.Average<PassengerFeedback>(i => i.GenericVote) >= 5
                    select u;


            foreach (User u in c)
            {
                Console.WriteLine(u.Id);
            }

        }

        [Test]
        public void TestSQL()
        {
            Stream s = new MemoryStream(ASCIIEncoding.Default.GetBytes("FROM Users WHERE Name Like \"pupp\" AND (Name like \"Drio\" or Username like \".l\" )"));
            Search.LOASQL.Scanner scanner = new Search.LOASQL.Scanner(s);
            Search.LOASQL.Parser parser = new Search.LOASQL.Parser(scanner);
            try
            {
                parser.Parse();

                if (parser.ExprType == typeof(User))
                {
                    Expression<Func<User, bool>> pred = Expression.Lambda<Func<User, bool>>(parser.Exp, parser.ExprParam);
                    IEnumerable<User> list = getDummyUsers().AsQueryable().Where<User>(pred);
                    Assert.AreEqual(1, list.Count<User>());
                }
                else
                {
                    Expression<Func<Trip, bool>> pred = Expression.Lambda<Func<Trip, bool>>(parser.Exp, parser.ExprParam);
                    //IEnumerable<Trip> list = getDummyUsers().AsQueryable().Where<Trip>(pred);
                    //Assert.AreEqual(1, list.Count<User>());
                }
            }
            catch (Exception e)
            {
                Assert.Fail();
                Console.WriteLine(e.Message);
            }
        }
    }

    public class VehicleComp : IEqualityComparer<Users_VehicleDetails>
    {

        #region IEqualityComparer<Vehicle> Members

        public bool Equals(Users_VehicleDetails x, Users_VehicleDetails y)
        {
            return x.Id == y.Id;
        }

        public int GetHashCode(Users_VehicleDetails obj)
        {
            return base.GetHashCode();
        }

        #endregion
    }
}
